package vip.xiaonuo.modular.manage.tsdatarecord.parser;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.springframework.stereotype.Component;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.modular.file.util.CommonFileUtils;
import vip.xiaonuo.modular.manage.tsdatarecord.entity.BaseMetadata;
import vip.xiaonuo.modular.manage.tsdatarecord.enums.FileParseExceptionEnum;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * ZipFileParser
 *
 * @author JackLee
 * 2022/8/5 15:55
 */
@Component
@Slf4j
public class ZipShapeFileParser implements FileParser {

    @Override
    public boolean available(String extension) {
        return CommonFileUtils.FileType.ZIP.equals(extension);
    }

    @Override
    public ParserResult parse(String filePath, Integer dealSize, String recordId, Consumer<List<BaseMetadata>> consumer) {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new ServiceException(FileParseExceptionEnum.NOT_EXIST);
        }
        ParserResult parserResult = new ParserResult();
        List<File> copyFiles = new ArrayList<>();
        SimpleFeatureIterator featureIterator = null;
        ShapefileDataStore store = null;
        File shpFile = null;
        try {
            //解压得到shp文件路径
            String shpFilePath = unzip(filePath, copyFiles);
            shpFile = new File(shpFilePath);
            store = new ShapefileDataStore(shpFile.toURI().toURL());
            //获取迭代器
            featureIterator = getIterator(store, parserResult);
            //解析
            doParse(featureIterator, dealSize, recordId, consumer, parserResult);
            log.info("文件解析完成！");
            return parserResult;
        } catch (Exception e) {
            log.error("文件解析失败！", e);
            throw new ServiceException(FileParseExceptionEnum.FILE_PARSE_ERROR);
        } finally {
            if (featureIterator != null)
                featureIterator.close();
            if (store != null)
                store.dispose();
            if (shpFile != null)
                shpFile.exists();
            file.exists();
            //删除解压的文件
            copyFiles.forEach(FileUtil::del);
        }
    }

    /**
     * 解压文件
     *
     * @param filePath
     * @param copyFiles
     * @return
     * @throws IOException
     */
    private String unzip(String filePath, List<File> copyFiles) throws IOException {
        ZipFile zipFile = null;
        String shpFilePath = "";
        try {
            zipFile = new ZipFile(filePath, Charset.forName("GBK"));
            Enumeration entries = zipFile.entries();

            String uuid = UUID.randomUUID().toString();//复制的文件目录
            while (entries.hasMoreElements()) {
                ZipEntry zipEntry = (ZipEntry) entries.nextElement();
                String copyFilePath = StringUtils.join(CommonFileUtils.fileRootPath, uuid, File.separator, zipEntry.getName());
                File copyFile = CommonFileUtils.copyInputStreamAndReturnFile(zipFile.getInputStream(zipEntry), copyFilePath);
                if (copyFilePath.endsWith(".shp")) {
                    shpFilePath = copyFilePath;
                }
                copyFiles.add(copyFile);
                log.info("压缩包中的文件：{}", copyFilePath);
            }
            //把复制的文件目录也添加  最后也要删除掉
            copyFiles.add(new File(CommonFileUtils.fileRootPath + uuid));
            if (StringUtils.isBlank(shpFilePath)) {
                //压缩包的文件不是shpfile
                log.error("zip包不是shpfile: {}", filePath);
                throw new ServiceException(FileParseExceptionEnum.NOT_SHPFILE);
            }
        } catch (IOException e) {
            throw new IOException(e);
        } finally {
            if (zipFile != null) {
                zipFile.close();
            }
        }
        return shpFilePath;
    }

    /**
     * 获取迭代器
     *
     * @param store
     * @param parserResult
     * @return
     * @throws IOException
     */
    private SimpleFeatureIterator getIterator(ShapefileDataStore store, ParserResult parserResult) throws IOException {
        store.setCharset(StandardCharsets.ISO_8859_1);
        SimpleFeatureSource sfSource = store.getFeatureSource();

        log.info("总共有{}条数据", sfSource.getFeatures().size());
        parserResult.setTotalCount(sfSource.getFeatures().size());
        return sfSource.getFeatures().features();
    }

    /**
     * 做解析
     *
     * @param featureIterator
     * @param dealSize
     * @param recordId
     * @param consumer
     * @param parserResult
     */
    private void doParse(SimpleFeatureIterator featureIterator, Integer dealSize, String recordId, Consumer<List<BaseMetadata>> consumer, ParserResult parserResult) {
        //获取属性值
        List<TableColumn> tableSchemas = new ArrayList<>();
        boolean notInit = true;

        if (dealSize == null || dealSize < 1) {
            dealSize = 1000;
        }
        List<BaseMetadata> dataList = new ArrayList<>(dealSize);
        String intoDate = DateUtil.now();
        int i = 0;
        int j = 0;
        while (featureIterator.hasNext()) {
            i++;
            if (i > dealSize) {
                i = 1;
            }
            SimpleFeature feature = featureIterator.next();
            Iterator<? extends Property> iterator = feature.getValue().iterator();
            Map<String, String> data = new HashMap<>();
            while (iterator.hasNext()) {
                j++;
                Property property = iterator.next();
                if (notInit) {
                    TableColumn schema = new TableColumn();
                    schema.setTitle(CommonFileUtils.getEncodingString(property.getName().toString()));
                    schema.setDataIndex("index" + j);
                    schema.setSort(j);
                    tableSchemas.add(schema);
                }
                String s = property.getValue().toString();

                data.put("index" + j, CommonFileUtils.getEncodingString(s));
            }
            BaseMetadata metadata = new BaseMetadata(recordId, JSON.toJSONString(data), intoDate);
            dataList.add(metadata);
            j = 0;
            notInit = false;
            if (i == dealSize) {
                consumer.accept(dataList);
                dataList = new ArrayList<>(dealSize);
            }
        }
        if (dataList.size() > 0) {
            consumer.accept(dataList);
        }
        parserResult.setColumnList(tableSchemas);
    }
}
